package com.tfkj.service;


import com.tfkj.entity.*;
import com.tfkj.repository.QuestionRepository;
import com.tfkj.repository.TestRepository;
import com.tfkj.repository.ImageRepository;
import com.tfkj.repository.StudentRepository;
import com.tfkj.vo.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class AllServiceImpl implements AllService{

    @Autowired
    private StudentRepository studentRepository;
    @Autowired
    private TestRepository testRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private QuestionRepository questionRepository;

    @Override
    public List<Student> findAllUser(String role, String className, String name, Integer pageNum, Integer pageSize) {
        if (name == null) {
            name = "";
        }
        return studentRepository.findAllMyUser(role, className, '%'+name+'%',(pageNum-1) * pageSize, pageSize);
    }


    @Transactional
    @Override
    public Integer insertStudentImageRel(InsertRelVO rel) {
        studentRepository.insertStudentImageRel(rel.getStudentNum(), rel.getTestId(), rel.getList());
        return 1;
    }

    @Override
    @Transactional
    public Integer updateStudentImageRel(Integer isError, Integer id) {
        return studentRepository.updateStudentImageRel(isError, id);
    }

    @Override
    public Student login(String studentNum, String password) {
        return studentRepository.findUserByLoginInfo(studentNum, password);
    }

    @Override
    @Transactional
    public List<ImageWithGradeAndSubjectVO> findImage(Integer testId) {
        return imageRepository.findAllByTestId(testId);
    }

    @Override
    @Transactional
    public Integer createImage(Integer testId, String url, Integer sortNum, Integer pageNum, String position, Double width, Double height, String resultPosition) {
        return imageRepository.insertImage(testId, url , sortNum, pageNum, position, width, height, "", "", 0, "", "");
    }

    @Override
    public Integer updateImage(Integer id, String grade, String subject, String questionType, Integer difficulty, String result) {
        return imageRepository.updateImage(id, grade, subject, questionType, difficulty, result);
    }

    @Override
    public Integer updateQuestion(Integer id, String grade, String subject, String questionType, Integer difficulty) {
        return questionRepository.updateQuestion(id, grade, subject, questionType, difficulty);
    }

    @Override
    public List<String> findUrlsWithSuggestion(List<Integer> idList, String type, Integer suggestionNum) {
        String ids = idList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(", "));
        Set<String> res = new HashSet<>();
        Set<String> typeSet = new HashSet<>();
        if ("image".equals(type)) {
            List<String> oldUrls = imageRepository.findUrlsById("("+ids+")");
            res.addAll(oldUrls);
            List<QuestionType> list = imageRepository.findQuestionTypeById("("+ids+")");
            if (CollectionUtils.isEmpty(list)) {
                return new ArrayList<>();
            }
            for (QuestionType type1 : list) {

                if (type1.getQuestionType().contains(",")){
                    String[] types = type1.getQuestionType().split(",");
                    // 创建一个Random对象
                    Random random = new Random();
                    // 从数组中随机选择一个元素
                    String randomType = types[random.nextInt(types.length)];
                    // 重新赋值给type1的questionType
                    type1.setQuestionType(randomType);
                }
                if (typeSet.contains(type1.getGrade()+type1.getSubject()+type1.getQuestionType())){
                    continue;
                }
                List<String> ress = imageRepository.findUrlsByIdWithSuggestion(type1, suggestionNum);
                if (!CollectionUtils.isEmpty(ress)){
                    res.addAll(ress);
                }
                typeSet.add(type1.getGrade()+type1.getSubject()+type1.getQuestionType());
            }
        } else {
            List<String> oldUrls = questionRepository.findUrlsById("("+ids+")");
            res.addAll(oldUrls);
            List<QuestionType> list = questionRepository.findQuestionTypeById("("+ids+")");
            if (CollectionUtils.isEmpty(list)) {
                return new ArrayList<>();
            }
            for (QuestionType type1 : list) {
                if (type1.getQuestionType().contains(",")){
                    String[] types = type1.getQuestionType().split(",");
                    // 创建一个Random对象
                    Random random = new Random();
                    // 从数组中随机选择一个元素
                    String randomType = types[random.nextInt(types.length)];
                    // 重新赋值给type1的questionType
                    type1.setQuestionType(randomType);
                }
                if (typeSet.contains(type1.getGrade()+type1.getSubject()+type1.getQuestionType())){
                    continue;
                }
                List<String> ress = questionRepository.findUrlsByIdWithSuggestion(type1, suggestionNum);
                if (!CollectionUtils.isEmpty(ress)){
                    res.addAll(ress);
                }
                typeSet.add(type1.getGrade()+type1.getSubject()+type1.getQuestionType());
            }
        }
        return res.stream().toList();
    }

    @Override
    @Transactional
    public Integer updateImageAndSaveQuestion(UpdateImageVO vo) {
        Integer i =  imageRepository.updateImageWithTestType(vo.getId(), vo.getGrade(), vo.getSubject(), vo.getQuestionType(), vo.getDifficulty(), vo.getResult(), vo.getTestType(), vo.getPageNum(), vo.getSortNum());
        System.out.println("保存成功，写入image："+i);
        Integer j = questionRepository.saveQuestionWithImageId(vo.getId());
        System.out.println("保存成功，同步question："+j);
        return i;
    }

    @Override
    public void relUpload(List<ExcelUploadVO> uploadVOS) {
        String testNum = uploadVOS.get(0).getTestNum();
        for (ExcelUploadVO vo : uploadVOS){
            System.out.println(vo);
            studentRepository.insertRelByUpload(testNum, vo.getStudentNUm(), vo.getVos());
        }
    }

    @Override
    public List<Student> findAllUser(String studentNum) {
        if (studentNum == null || "".equals(studentNum)) {
            return new ArrayList<>();
        }
        studentNum.replaceAll("，",",");
        return studentRepository.findUserByNums("("+studentNum+")");
    }

    @Override
    public List<RelAndImageVO> findImages(String findUrlStudentStr, LocalDate startDate, LocalDate endDate) {
        return studentRepository.findImages("("+findUrlStudentStr+")", startDate.atTime(0,0,0), endDate.atTime(23,59,59));
    }

    @Override
    public String findStudentIds(String className) {
        List<String> ids = studentRepository.findStudentIds(className);
        if (CollectionUtils.isEmpty(ids)){
            return "";
        }
        return String.join(",", ids);
    }

    @Override
    @Transactional
    public List<RelAndImageVO> findSuggestions(String findUrlStudentStr, LocalDate startDate, LocalDate endDate) {
        List<RelAndImageVO> rels = new ArrayList<>();
        List<String> studentNumstr = Arrays.stream(findUrlStudentStr.split(",")).toList();
        List<Suggestion> suggestions = questionRepository.suggestionSearchAll(studentNumstr, startDate.atTime(0,0,0), endDate.atTime(23,59,59));
        if (CollectionUtils.isEmpty(suggestions)){
            return rels;
        }
        String distinctQuestionIds = suggestions.stream()
                .map(Suggestion::getQuestionIds)      // 提取每个元素的questionIds
                .flatMap(ids -> Arrays.stream(ids.split(","))) // 拆分逗号分隔的字符串
                .distinct()                            // 6. 去重（保留首次出现顺序）
                .collect(Collectors.joining(","));
        List<Question> que = questionRepository.findUrlsAndIdById("("+distinctQuestionIds+")");
        Map<Integer, String> questionUrlMap = que.stream()
                .collect(Collectors.toMap(Question::getId, Question::getUrl));
        // 2. 核心处理流程
        rels = suggestions.stream()
                // 展开多个学生与题目的关联
                .flatMap(suggestion -> {
                    // 拆分学生编号
                    Set<String> studentNums = splitString(suggestion.getStudentIds());
                    // 拆分题目ID
                    Set<Integer> questionIds = splitStringToInt(suggestion.getQuestionIds());

                    // 笛卡尔积组合学生与题目
                    return studentNums.stream()
                            .flatMap(student -> questionIds.stream()
                                    .map(questionId -> Pair.of(student, questionId)));
                })
                // 过滤有效题目（存在url的题目）
                .filter(pair -> questionUrlMap.containsKey(pair.getRight()))
                // 转换为VO对象
                .map(pair -> new RelAndImageVO(pair.getLeft(), questionUrlMap.get(pair.getRight())))
                // 去重（需VO实现equals/hashCode）
                .distinct()
                .collect(Collectors.toList());

        return rels;
    }

    // 辅助方法：拆分字符串并去重
    private Set<String> splitString(String input) {
        if (input == null || input.trim().isEmpty()) return Collections.emptySet();
        return Arrays.stream(input.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toSet());
    }

    // 辅助方法：拆分字符串转整数并去重
    private Set<Integer> splitStringToInt(String input) {
        if (input == null || input.trim().isEmpty()) return Collections.emptySet();
        return Arrays.stream(input.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(Integer::parseInt)
                .collect(Collectors.toSet());
    }

    // 临时Pair类（如果项目没有可替换为AbstractMap.SimpleEntry）
    @Data
    @AllArgsConstructor
    static class Pair<L, R> {
        private L left;
        private R right;

        public static <L, R> Pair<L, R> of(L left, R right) {
            return new Pair<>(left, right);
        }
    }
    @Override
    public List<Question> findQuestion(String grade, String subject, String questionType, Integer difficulty, Integer pageNum, Integer pageSize) {
        if (questionType != null && !"".equals(questionType)) {
            List<String> questionTypes = Arrays.asList(questionType.split(","));
            return questionRepository.findQuestions(grade, subject, questionTypes, difficulty, (pageNum-1) * pageSize, pageSize);
        }
        return questionRepository.findQuestions(grade, subject, null, difficulty, (pageNum-1) * pageSize, pageSize);

    }

    @Override
    public Integer findQuestionTotal(String grade, String subject, String questionType, Integer difficulty) {
        if (questionType != null && !"".equals(questionType)) {
            List<String> questionTypes = Arrays.asList(questionType.split(","));
            return questionRepository.findQuestionsTotal(grade, subject, questionTypes, difficulty);
        }
        return questionRepository.findQuestionsTotal(grade, subject, null, difficulty);

    }

    @Override
    public List<Question> findQuestionRandom(String grade, String subject, String questionType, Integer difficulty) {
        if (questionType != null && !"".equals(questionType)) {
            List<String> questionTypes = Arrays.asList(questionType.split(","));
            return questionRepository.findQuestionsRandom(grade, subject, questionTypes, difficulty, difficulty+1, difficulty+2);
        }
        return questionRepository.findQuestionsRandom(grade, subject, null, difficulty, difficulty+1, difficulty+2);
    }

    @Override
    public List<QuestionType> findQuestionType() {
        return questionRepository.findQuestionsType();
    }



    @Override
    public List<Test> getTests(String name, Integer pageNum, Integer pageSize) {
        List<Test> ts = new ArrayList<>();
        if (name == null) {
            ts = testRepository.findTests((pageNum-1) * pageSize, pageSize);
        } else {
            ts = testRepository.findTestsByKey(name, (pageNum-1) * pageSize, pageSize);
        }
        return ts;
    }
    @Transactional
    public Integer updateTest(int id, String name, String grade, String subject) {
        return testRepository.updateTest(id, name, grade, subject);
    }

    @Transactional
    @Override
    public Integer updateTestUrls(Integer id, String urls) {
        return testRepository.updateTestUrls(id, urls);
    }
    @Override
    @Transactional
    public Integer createTest(String name, String grade, String subject, String urls, String type, String testNum) {
        if (type == null) {
            type = "";
        }
        if (testNum == null) {
            testNum = "";
        }
        return testRepository.insertTest(name, grade, subject, urls, type, testNum);
    }

    @Override
    public Integer insertTestWithId(Integer id, String name, String grade, String subject, String urls) {
        return testRepository.insertTestWithId(id, name, grade, subject, urls);
    }

    @Override
    public List<RelShowVO> findErrorList(String studentNum, String grade, String className, String subject, List<String>  questionTypes, Integer difficulty, Integer pageNum, Integer pageSize, LocalDate startTime, LocalDate endTime) {
        List<RelVO> list;
        if (startTime == null || endTime == null) {
            list = studentRepository.findStudentImageRel(studentNum, grade, className, subject, questionTypes, difficulty,(pageNum-1) * pageSize, pageSize, null, null);
        }else {
            list = studentRepository.findStudentImageRel(studentNum, grade, className, subject, questionTypes, difficulty,(pageNum-1) * pageSize, pageSize, startTime.atTime(0,0,0), endTime.atTime(23,59,59));
        }
        List<RelShowVO> res = new ArrayList<>();
        Map<Integer, RelShowVO> idToShowVoMap = new HashMap<>();
        for (RelVO vo : list) {
            int id = vo.getId();
            String name = vo.getName();
            if (idToShowVoMap.containsKey(id)) {
                // 合并已有条目：拼接 names 并累加 num
                RelShowVO existing = idToShowVoMap.get(id);
                existing.setNames(existing.getNames() + "," + name);
                existing.setNum(existing.getNum() + 1);
            } else {
                // 创建新条目：继承父类属性，初始化 names 和 num
                RelShowVO newShowVo = new RelShowVO();
                newShowVo.setId(id);
                newShowVo.setUrl(vo.getUrl());
                newShowVo.setGrade(vo.getGrade());
                newShowVo.setSubject(vo.getSubject());
                newShowVo.setQuestionType(vo.getQuestionType());
                newShowVo.setDifficulty(vo.getDifficulty());
                newShowVo.setNames(name);
                newShowVo.setNum(1);
                newShowVo.setName(null); // 显式清空父类 name
                idToShowVoMap.put(id, newShowVo);
            }
        }
        res.addAll(idToShowVoMap.values());
        return res;
    }

    @Override
    public void deleteTest(Integer id) {
        testRepository.deleteTest(id);
    }

    @Override
    public Integer updateUser(String studentNum, String password, String oldPassword) {
        return studentRepository.updatePassword(studentNum, password, oldPassword);
    }

    @Override
    public void deleteStudentImageRel(Integer id) {
        studentRepository.deleteRel(id);
    }

    @Override
    public void deleteQuestion(Integer id) {
        questionRepository.deleteById(id);
    }

    @Override
    public Integer getTestsTotal(String name) {
        Integer total = 0;
        if (name == null) {
            total = testRepository.findTestsTotal();
        } else {
            total = testRepository.findTestsByKeyTotal(name);
        }
        return total;
    }

    @Override
    public Integer getStudentTotal(String role, String className, String name) {
        if (name == null) {
            name = "";
        }
        return studentRepository.findAllMyUserTotal(role, className, '%'+name+'%');
    }


    @Override
    public Integer findErrorListTotal(String studentNum, String grade, String className, String subject,List<String> questionTypes, Integer difficulty, LocalDate startTime, LocalDate endTime) {
        if (startTime == null || endTime == null) {
            return studentRepository.findStudentImageRelTotal(studentNum, grade, className, subject, questionTypes, difficulty, null, null);
        }else {
            return studentRepository.findStudentImageRelTotal(studentNum, grade, className, subject, questionTypes, difficulty, startTime.atTime(0,0,0), endTime.atTime(23,59,59));
        }
    }


    @Override
    @CacheEvict(value = "questionTypeCache", allEntries = true)
    public void deleteQuestionType(Integer id) {
        questionRepository.deleteType(id);
    }

    @Override
    @CacheEvict(value = "questionTypeCache", allEntries = true)
    public void createQuestionType(QuestionType questionType) {
        questionRepository.createType(questionType.getGrade(), questionType.getSubject(), questionType.getQuestionType());
    }

    @Override
    public QuestionEnumerationVO findQuestiontypeEnumeration() {
        List<QuestionType> questionTypes = questionRepository.findQuestionsType();
        Set<String> grade = new HashSet<>();
        Set<String> subject = new HashSet<>();
        for (QuestionType questionType : questionTypes) {
            grade.add(questionType.getGrade());
            subject.add(questionType.getSubject());
        }
        QuestionEnumerationVO qe = new QuestionEnumerationVO();
        qe.setGrade(grade.stream().toList());
        qe.setSubject(subject.stream().toList());
        return qe;
    }

    @Transactional
    @Override
    public void insertQuestions(List<Question> questionList) {
        for (Question q : questionList) {
            questionRepository.insertQuestion(q.getTestId(), q.getUrl());
        }

    }

    @Override
    public void createUser(Student student) {
        studentRepository.createStudent(student.getGrade(), student.getName(), student.getClassName().replace('，',','), student.getRole(), student.getStudentNum(), student.getSubject());
    }

    @Override
    public void updateUserInfo(String studentNum, String phone, String email) {
        studentRepository.updateInfo(studentNum,phone,email);
    }

    @Override
    public void createImage(List<CreateImageVO> imageList, Integer testId) {

        for (CreateImageVO imageVO : imageList) {
            System.out.println(imageVO.getSortNum());
            System.out.println(imageVO.getResultPosition());
            if (imageVO.getScore() == null) {
                imageRepository.insertImageNew(testId, imageVO.getUrl(), imageVO.getSortNum(), imageVO.getPageNum(), imageVO.getPosition(), imageVO.getWidth(), imageVO.getHeight(), imageVO.getResultPosition(), imageVO.getQuestionModel(), imageVO.getGrade(), imageVO.getSubject());
            } else {
                imageRepository.insertImage(testId, imageVO.getUrl(), imageVO.getSortNum(), imageVO.getPageNum(), imageVO.getPosition(), imageVO.getWidth(), imageVO.getHeight(), imageVO.getResultPosition(), imageVO.getQuestionModel(), imageVO.getScore(), imageVO.getGrade(), imageVO.getSubject());
            }
        }
    }

    @Override
    public List<String> findGrade() {
        return questionRepository.findGrades();
    }


    @Override
    public List<String> findSubject(String grade) {
        return questionRepository.findSubject(grade);
    }

    @Override
    public List<Question> findQuestionWithSubject(String grade, String subject, Integer pageNum, Integer pageSize) {
        return questionRepository.findQuestionsWithSubject(grade, subject, (pageNum-1) * pageSize, pageSize);

    }

    @Override
    public Integer findQuestionWithSubjectTotal(String grade, String subject) {
        return questionRepository.findQuestionsWithSubjectTotal(grade, subject);
    }

    @Override
    @Cacheable(value = "questionTypeCache", key = "#grade + '-' + #subject")
    public List<QuestionType> findQuestionType(String grade, String subject) {
        return questionRepository.findQuestionType(grade, subject);
    }


    @Override
    public List<String> findUrls(List<Integer> idList, String type) {
        String ids = idList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(", "));
        if ("image".equals(type)) {
            return imageRepository.findUrlsById("("+ids+")");
        } else {
            return questionRepository.findUrlsById("("+ids+")");
        }
    }

    @Override
    public Integer findMaxTestId() {
        return testRepository.findMaxTestId();
    }

    @Override
    public void suggestion(String teacherNum, String questionIds, String studentIds) {
        questionRepository.suggestion(teacherNum, questionIds, studentIds);
    }

    @Override
    public List<QuestionSuggestionVO> suggestionSearch(String studentNum, String teacherNum, LocalDate createDate) {
        List<Suggestion> suggestions = questionRepository.suggestionSearch('%'+studentNum+'%', teacherNum, createDate);
        List<QuestionSuggestionVO> res = new ArrayList<>();
        if (suggestions != null && !suggestions.isEmpty()) {
            for (Suggestion s:suggestions) {
                List<QuestionSuggestionVO> ress;
                ress = questionRepository.findQuestionsBySIds(s.getId());
                res.addAll(ress);
            }
        }
        return res;
    }

    @Override
    public List<Student> findTeacherList(String className) {
        return studentRepository.findTeacherList('%'+className+'%');
    }
}
